﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Management;
using System.IO.Ports;
using Neurokinetic.NeuroSkyNet.Controller;

namespace Neurokinetic.NeuroSkyNet.Model
{
    /// <summary>
    /// NeuroSky MindSet Integration Class
    /// </summary>
    public class MindSetModel : IEnumerable<MindSetDataModel>, INotifyPropertyChanged, IDisposable
    {
        protected MindSetDataModel[] Items
        {
            get;
            private set;
        }
        public MindSetDataModel Battery
        {
            get
            {
                return this[(Int32)MindSetDataType.Battery];
            }
        }
        public MindSetDataModel Signal
        {
            get
            {
                return this[(Int32)MindSetDataType.Signal];
            }
        }
        public MindSetDataModel Attention
        {
            get
            {
                return this[(Int32)MindSetDataType.Attention];
            }
        }
        public MindSetDataModel Meditation
        {
            get
            {
                return this[(Int32)MindSetDataType.Meditation];
            }
        }
        public MindSetDataModel Raw
        {
            get
            {
                return this[(Int32)MindSetDataType.Raw];
            }
        }
        public MindSetDataModel Delta
        {
            get
            {
                return this[(Int32)MindSetDataType.Delta];
            }
        }
        public MindSetDataModel Theta
        {
            get
            {
                return this[(Int32)MindSetDataType.Theta];
            }
        }
        public MindSetDataModel Alpha1
        {
            get
            {
                return this[(Int32)MindSetDataType.Alpha1];
            }
        }
        public MindSetDataModel Alpha2
        {
            get
            {
                return this[(Int32)MindSetDataType.Alpha2];
            }
        }
        public MindSetDataModel Beta1
        {
            get
            {
                return this[(Int32)MindSetDataType.Beta1];
            }
        }
        public MindSetDataModel Beta2
        {
            get
            {
                return this[(Int32)MindSetDataType.Beta2];
            }
        }
        public MindSetDataModel Gamma1
        {
            get
            {
                return this[(Int32)MindSetDataType.Gamma1];
            }
        }
        public MindSetDataModel Gamma2
        {
            get
            {
                return this[(Int32)MindSetDataType.Gamma2];
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public MindSetDataModel this[MindSetDataType dataType]
        {
            get
            {
                return this.Items[(Int32)dataType];
            }
            private set
            {
                this.Items[(Int32)dataType] = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public MindSetDataModel this[Int32 index]
        {
            get
            {
                return this.Items[index];
            }
            private set
            {
                this.Items[index] = value;
            }
        }
        /// <summary>
        /// API Connection ID
        /// </summary>
        public Int32 ConnectionID
        {
            get;
            private set;
        }

        /// <summary>
        /// Packets Read Last Connection
        /// </summary>
        public Int32 PacketsRead
        {
            get;
            private set;
        }

        /// <summary>
        /// Port MindSet is Connected on
        /// </summary>
        public String Port
        {
            get;
            private set;
        }

        /// <summary>
        /// Ticks
        /// </summary>
        public Int32 Ticks
        {
            get;
            private set;
        }

        /// <summary>
        /// Packets Read Last Connection
        /// </summary>
        public DateTime DatePacketsRead
        {
            get;
            private set;
        }

        /// <summary>
        /// Packets Read Last Connection
        /// </summary>
        internal void SetPacketsRead(Int32 packetsRead)
        {
            if (packetsRead <= 0)
                throw new Exception("PacketsRead must be more then 0");

            DatePacketsRead = DateTime.Now;
            NotifyPropertyChanged("DatePacketsRead");

            PacketsRead = packetsRead;
            NotifyPropertyChanged("PacketsRead");
        }

        /// <summary>
        /// Packets Read Last Connection
        /// </summary>
        internal void Update(MindSetDataType type, float value)
        {
            Ticks++;
            NotifyPropertyChanged("Ticks");

            if (Controller.MindSetController.Mode == MindSetModeType.Raw || Controller.MindSetController.Mode == MindSetModeType.RawWithLogs || type == MindSetDataType.Signal || this.Signal.Current != 200)
            {
                // No data filtering if program is running in Raw Mode
                this[type].Add(value);
                return;
            }
        }

        /// <summary>
        /// Default MindSet Constructor
        /// </summary>
        /// <param name="connectionID"></param>
        internal MindSetModel(Int32 connectionID, String port)
        {
            this.ConnectionID = connectionID;
            this.Port = port;
            this.Items = new MindSetDataModel[Enum.GetValues(typeof( MindSetDataType)).Length];
            foreach (MindSetDataType dataType in Enum.GetValues(typeof(MindSetDataType)))
                this[dataType] = new MindSetDataModel(dataType);
        }

        #region | IDisposable Implementation | Free MindSet connection
        public void Dispose()
        {
            MindSetController.Disconnect(this);
            GC.SuppressFinalize(this);
        }
        #endregion

        #region | IEnumerable<MindSetDataModel> Implementation | Enables use in loops
        public IEnumerator<MindSetDataModel> GetEnumerator()
        {
            foreach (var item in Items)
                yield return item;
        }
        #endregion

        #region  | IEnumerable | Enables use in loops
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
        #endregion

        #region  | INotifyPropertyChanged Implementation | Notifies view of changes
        private void NotifyPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion

    }
}
